package pro.cherish.quartzlockdemo.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import pro.cherish.quartzlockdemo.da.GiveBack;
import pro.cherish.quartzlockdemo.da.InitQuartzJob;
import pro.cherish.quartzlockdemo.da.ScheduleJob;
import pro.cherish.quartzlockdemo.entity.STimetask;
import pro.cherish.quartzlockdemo.service.STimetaskService;
import pro.cherish.quartzlockdemo.util.UUIDGenerator;

import java.util.Date;
import java.util.List;

@Controller
@RequestMapping(value = "/admin/task")
@Api(tags = "管理时间任务")
@Slf4j
public class ManageTimetaskController {
    @Autowired
    STimetaskService sTimetaskService;
    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    /**
     * 增加定时任务
     *
     * @return
     */
    @PostMapping("add")
    @ResponseBody
    public GiveBack add(String name, String desccription, String cron, String jobStatus, String jobData, String methodName) {
        String code = "";
        String message = "";
        String data = null;
        try {
            if (StringUtils.isBlank(name) || StringUtils.isBlank(desccription) || StringUtils.isBlank(cron)
                    || StringUtils.isBlank(jobStatus) || StringUtils.isBlank(jobData) || StringUtils.isBlank(methodName)
            ) {
                code = "200";
                message = "必要参数为空";
                return GiveBack.make(code, message, data);
            }
            if (name.length() > 50 || desccription.length() > 1000 || (!isValidExpression(cron)) || (!isOne(jobStatus))
                    || jobData.length() > 2000) {
                code = "201";
                message = "参数异常";
                return GiveBack.make(code, message, data);
            }

            String[] ipList = jobData.split(",");
            for (int i = 0; i < ipList.length; i++) {
                String tempIp = ipList[i];
                if (!isIP(tempIp)) {
                    code = "201";
                    message = "jobData异常";
                    return GiveBack.make(code, message, data);
                }
            }

            STimetask record = new STimetask();
            record.setId(UUIDGenerator.generate());

            record.setName(name);
            record.setGroupName("pdu");
            Date date = new Date();
            record.setStartTime(date);
            record.setEndTime(date);
            record.setCron(cron);
            record.setJobStatus(jobStatus);
            record.setIsConcurrent(0);
            record.setPlanStatus("-1");
            record.setJobData(jobData);
            record.setMethodName(methodName);

            record.setBeanName("com.utils.tprs_pdu.TPRSOrderSendHelper");
            record.setDesccription(desccription);
            record.setCreateUserId("cherish");
            record.setCreateDate(date);
            int i = sTimetaskService.insertSelective(record);
            if (i < 1) {
                code = "1";
                message = "请求成功但未发生任何更改";
                return GiveBack.make(code, message, data);
            }
            code = "0";
            return GiveBack.make(code, message, data);
        } catch (Exception e) {
            log.error(e.toString());
            code = "-1";
            message = "系统异常";
            return GiveBack.make(code, message, data);
        }
    }

    /**
     * 删除定时任务
     *
     * @return
     */
    @PostMapping("del")
    @ResponseBody
    public GiveBack del(String id) {
        String code = "";
        String message = "";
        String data = null;

        try {
            String[] idList = id.split(",");
            JSONArray arr = new JSONArray();
            code = "0";
            for (int i = 0; i < idList.length; i++) {
                JSONObject json = new JSONObject();
                String singleId = idList[i];
                final STimetask sTimetask = sTimetaskService.selectByPrimaryKey(singleId);
                final String name = sTimetask.getName();
                final String groupName = sTimetask.getGroupName();
                sTimetaskService.deleteByPrimaryKey(singleId);
                Scheduler scheduler = schedulerFactoryBean.getScheduler();
                JobKey jobKey = JobKey.jobKey(name, groupName);
                try {
                    scheduler.deleteJob(jobKey);
                } catch (SchedulerException e1) {
                    e1.printStackTrace();
                    code = "-1";
                    json.put(singleId, "系统异常导致任务删除成功,但计划仍在执行,请联系管理员");
                }
                arr.add(json);
            }
            data = arr.toJSONString();
            return GiveBack.make(code, message, data);
        } catch (Exception e) {
            code = "-1";
            message = "系统异常";
            return GiveBack.make(code, message, data);
        }
    }

    /**
     * 更新定时任务
     *
     * @return
     */
    @PostMapping("update")
    @ResponseBody
    public GiveBack update(String id,
                           String name,
                           String desccription,
                           String cron,
                           String jobStatus,
                           String jobData,
                           String methodName) {
        String code = "";
        String message = "";
        String data = null;
        if (StringUtils.isBlank(name) || StringUtils.isBlank(desccription) || StringUtils.isBlank(cron)
                || StringUtils.isBlank(jobStatus) || StringUtils.isBlank(jobData) || StringUtils.isBlank(methodName)
        ) {
            code = "200";
            message = "必要参数为空";
            return GiveBack.make(code, message, data);
        }
        if (name.length() > 50 || desccription.length() > 1000 || (!isValidExpression(cron)) || (!isOne(jobStatus))
                || jobData.length() > 2000 || (!checkMethodName(methodName))) {
            code = "201";
            message = "参数异常";
            return GiveBack.make(code, message, data);
        }

        STimetask record = new STimetask();
        record.setId(id);
        record.setName(name);
        record.setGroupName("pdu");
        Date date = new Date();
        record.setStartTime(date);
        record.setEndTime(date);
        record.setCron(cron);
        record.setJobStatus(jobStatus);
        record.setJobData(jobData);
        record.setMethodName(methodName);

        record.setBeanName("com.utils.tprs_pdu.TPRSOrderSendHelper");
        record.setDesccription(desccription);
        record.setModifyUserId("cherish");
        record.setModifyDate(date);
        int i = sTimetaskService.updateByPrimaryKeySelective(record);
        if (i < 1) {
            code = "1";
            message = "请求成功但未发生任何更改";
            return GiveBack.make(code, message, data);
        } else {
            code = "0";
            threadPoolTaskExecutor.execute(new Thread(id) {
                @Override
                public void run() {
                    STimetask sTimetask = sTimetaskService.selectByPrimaryKey(id);
                    if ("1".equals(sTimetask.getJobStatus()) && "1".equals(sTimetask.getPlanStatus())
                            && "1".equals("" + sTimetask.getIsConcurrent())) {
                        Scheduler scheduler = schedulerFactoryBean.getScheduler();
                        JobKey jobKey = JobKey.jobKey(sTimetask.getName(), sTimetask.getGroupName());
                        try {
                            scheduler.deleteJob(jobKey);
                        } catch (SchedulerException e1) {
                            e1.printStackTrace();
                        }
                        ScheduleJob job1 = new ScheduleJob();
                        job1.setJobId(sTimetask.getId());
                        job1.setJobGroup(sTimetask.getGroupName()); // 任务组
                        job1.setJobName(sTimetask.getName());// 任务名称
                        job1.setJobStatus(sTimetask.getJobStatus()); // 任务发布状态
                        job1.setIsConcurrent(sTimetask.getIsConcurrent() == 1 ? "1" : "0"); // 运行状态
                        // 1:run
                        // 0:stop
                        job1.setCronExpression(sTimetask.getCron());
                        job1.setBeanClass(sTimetask.getBeanName());// 一个以所给名字注册的bean的实例
                        job1.setMethodName(sTimetask.getMethodName());
                        job1.setJobData(sTimetask.getJobData()); // 参数
                        try {
                            InitQuartzJob.addJob(job1);
                        } catch (SchedulerException e) {
                            e.printStackTrace();
                        }
                        sTimetask.setIsConcurrent(1);
                        sTimetask.setPlanStatus("1");
                        sTimetaskService.updateByPrimaryKeySelective(sTimetask);
                    }
                }
            });
            return GiveBack.make(code, message, data);
        }
    }


    @PostMapping("get")
    @ResponseBody
    public GiveBack get(String pageNumStr, String pageSizeStr, String name, String jobStatus) {
        String code = "";
        String message = "";
        String data = null;
        try {

            QueryWrapper<STimetask> queryWrapper = new QueryWrapper<>();
            if (StringUtils.isNotEmpty(name)) {
                queryWrapper.eq("name", "%" + name + "%");
            }
            out:
            if (StringUtils.isNotEmpty(jobStatus)) {
                if ("-1".equals(jobStatus)) {
                    break out;
                }
                if (!"1".equals(jobStatus) && !"0".equals(jobStatus)) {
                    code = "201";
                    message = "参数异常";
                    return GiveBack.make(code, message, data);
                }
                queryWrapper.eq("job_status", jobStatus);
            }
            int pageNum = 0;
            int pageSize = 0;
            try {
                pageNum = Integer.parseInt(pageNumStr);
                pageSize = Integer.parseInt(pageSizeStr);
            } catch (Exception e) {
                code = "100";
                message = "类型转换异常";
                return GiveBack.make(code, message, data);
            }
            IPage<STimetask> page = sTimetaskService.page(new Page<>(pageNum, pageSize), queryWrapper);
            List<STimetask> list = page.getRecords();
            JSONObject json = new JSONObject();
            json.put("pages", page.getPages());
            json.put("totals", page.getTotal());
            message = json.toString();
            JSONArray arr = new JSONArray();
            if (list.size() == 0) {
                data = "";
            } else {
                for (int i = 0; i < list.size(); i++) {
                    JSONObject json2 = new JSONObject();
                    STimetask s = list.get(i);
                    json2.put("id", s.getId());
                    json2.put("desccription", s.getDesccription() == null ? "" : s.getDesccription());
                    json2.put("name", s.getName() == null ? "" : s.getName());
                    json2.put("cron", s.getCron() == null ? "" : s.getCron());
                    json2.put("jobStatus", s.getJobStatus() == null ? "" : s.getJobStatus());
                    json2.put("isCon", s.getIsConcurrent() == null ? "" : s.getIsConcurrent());
                    json2.put("planStatus", s.getPlanStatus() == null ? "" : s.getPlanStatus());
                    json2.put("jobData", s.getJobData() == null ? "" : s.getJobData());
                    json2.put("methodName", s.getMethodName() == null ? "" : s.getMethodName());
                    json2.put("createUserId", s.getCreateUserId() == null ? "" : s.getCreateUserId());
                    json2.put("createTime", s.getCreateDate().toLocaleString() == null ? "" : s.getCreateDate().toLocaleString());
                    json2.put("modifyUserId", s.getModifyUserId() == null ? "" : s.getModifyUserId());
                    json2.put("modifyTime", s.getModifyDate() == null ? "" : s.getModifyDate());
                    arr.add(json2);
                }
            }
            code = "0";
            return GiveBack.make(code, message, arr);
        } catch (Exception e) {
            e.printStackTrace();
            code = "-1";
            message = e.toString();
            return GiveBack.make(code, message, data);
        }
    }


    private static boolean isOne(String str) {
        return "1".equals(str) || "0".equals(str) ? true : false;
    }

    private static boolean checkMethodName(String str) {
        if (StringUtils.isBlank(str)) {
            return false;
        }
        String[] names = {"open", "close"};
        boolean res = false;
        for (int i = 0; i < names.length; i++) {
            if (str.equals(names[i])) {
                res = true;
            }
        }
        return res;
    }

    private static boolean isValidExpression(final String cronExpression) {
        CronTriggerImpl trigger = new CronTriggerImpl();
        try {
            trigger.setCronExpression(cronExpression);
            Date date = trigger.computeFirstFireTime(null);
            return date != null && date.after(new Date());
        } catch (Exception e) {
            log.error("[TaskUtils.isValidExpression]:failed. throw ex:" + e);
        }
        return false;
    }

    private static boolean isIP(String ip) {
        String rexp = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
        return ip.matches(rexp);
    }

}